/*---------------------------------------------------------------------------------------------------------*/
/*                                                                                                         */
/* Copyright(c) 2017 Nuvoton Technology Corp. All rights reserved.                                         */
/*                                                                                                         */
/*---------------------------------------------------------------------------------------------------------*/

//***********************************************************************************************************
//  Nuvoton Technoledge Corp. 
//  Website: http://www.nuvoton.com
//  E-Mail : MicroC-8bit@nuvoton.com
//  Date   : Apr/21/2017
//***********************************************************************************************************

//***********************************************************************************************************
//  File Function: N76E003 I/O Interrupt demo code
//***********************************************************************************************************

#include "N76E003.h"
#include "SFR_Macro.h"
#include "Function_define.h"
#include "Common.h"
#include "Delay.h"
#include "String.h"
#include "Celluar.h"

#define TX_TIME  5
#define POWER_DOWN_TIME  5
//#define DEBUG	1

typedef struct{
  UINT8 reserved[5];
  UINT8 end;
}DataType;  // for example

typedef struct 
{
    UINT8               ucHeader[2];            // message head'UC' 
    UINT8               ucCmdCode;              // id 0-timer,1-cut 2-faraway,3-request
    union{ 
      UINT8 end;																// message end
      DataType buffer;
    
    }Data; 
    
}App_Send_TypeDef;

typedef enum{
	SEND_REQ = 0,
	SEND_MSG,
	PD,
	CUT,
	FARAWAY,
	WAIT,
	COUNTER
}SysMode;

typedef enum{
	PEND = 0,
	READY,
	END
}UartRxMode;

typedef enum{
	POSTION = 0,
	CUT_WIRE,
	FAR_AWAY,
	REQ_RESP	
}MsgType;

typedef enum{
	RET_OK = 0,
	RET_ERROR,
	RET_TIME
}MsgRegType;

typedef struct {
	SysMode mode;
	UINT32 TransTimeCounter;
	UINT32 pdIntCounter;
	UINT32 PowerON6261WaitCnt;
	UINT32 Respon6261WaitCnt;
	UINT32 wakeupCnt;
	UINT8 moduleStatus;
	MsgType msgType;
	UartRxMode uartRxMode;
}globalStr;

globalStr global;

extern UINT8  UART0_RxBuf[RX_BUFFER_SIZE];
extern UINT16 u16RxCnt;
volatile UINT32 u32WakeupCounter = 0;

void App_GlobalInit(void)
{
	global.mode = SEND_REQ;
	global.TransTimeCounter = TX_TIME;
	global.pdIntCounter = POWER_DOWN_TIME;
	global.moduleStatus = 0;
	global.wakeupCnt = 0;
	global.msgType = POSTION;
	global.uartRxMode = PEND;
	global.PowerON6261WaitCnt = 100;
	global.Respon6261WaitCnt = 50;
}
	
void App_EvbLedConfig(void)
{
	P12_PushPull_Mode;
}

void App_EvbLedOFF(void)
{
	P12 = 0;
}

void App_EvbLedON(void)
{
	P12 = 1;
}

void App_EvbLedBlink(void)
{
	P12 = ~P12;
}

void App_GlobalInterrupEnable(void)
{
	set_EA;								
}

void App_GlobalInterrupDisable(void)
{
	clr_EA;
}
#if 1
void SerialPort0_ISR(void) interrupt 4 
{
		UINT8 tmp;
    if (RI==1) 
    {
			clr_RI;
			tmp = SBUF;
			if(u16RxCnt >= RX_BUFFER_SIZE){
					clr_ES;
					u16RxCnt = 0;
			}
			switch(global.uartRxMode){
				case PEND:
					if(tmp == 'U'){
						global.uartRxMode = READY;
						UART0_RxBuf[u16RxCnt++] = tmp;
					}
					break;
				case READY:
					if(tmp != 0xAA){
						UART0_RxBuf[u16RxCnt++] = tmp;
					}
					else{
						UART0_RxBuf[u16RxCnt++] = tmp;
						global.uartRxMode = END;
						clr_ES;
						u16RxCnt = 0;
					}
					break;
				case END:
					break;
				default:
					break;					
			}
    }
    if(TI==1)
    {
        clr_TI;                             /* if emission occur */
    }
}

void App_ClearRxBuffer(void)
{
	memset(UART0_RxBuf, 0x00, RX_BUFFER_SIZE);
	u16RxCnt = 0;
}

#endif

UINT8 WKT_FLAG = 0;
void WakeUp_Timer_ISR (void)   interrupt 17     //ISR for self wake-up timer
{
		u32WakeupCounter++;

		clr_WKTR;
	  clr_WKTF;                    		           //clear interrupt flag   
}


void SerialPort0EnableInt(void)
{
	set_ES;
}

void SerialPort0DisableInt(void)
{
	clr_ES;
}
/******************************************************************************
 * FUNCTION_PURPOSE: I/O Pin interrupt Service Routine
 ******************************************************************************/


void App_SendString(unsigned char *str,unsigned int strlen)
{
    unsigned int k=0; 
    do 
    {
        Send_Data_To_UART0(*(str + k));
        k++;
    } while(k < strlen);
}

void App_Uart0SendStrings(unsigned char *s)
{
#ifdef DEBUG	
	while(*s){
		Send_Data_To_UART0_Debug(*s++);
	}
#endif	
}

int cnt1 = 0;
int cnt2 = 0;
unsigned char gCutWireFlag = 0;
unsigned char gFarAwayFlag = 0;
void PinInterrupt_ISR (void) interrupt 7
{
	UINT8 i, flag1=0, flag2=0;
	if(PIF == 0x20){ // PIN5
		PIF = 0x00;                             //clear interrupt flag 
//		cnt1++;
//		gCutWireFlag = 1;
		//global.mode = CUT;
		global.msgType = CUT_WIRE;
	}
	else if(PIF == 0x80){ // PIN7    
		for(i = 0; i<50; i++){
			Timer0_Delay1ms(500);
			if(P17 == 1){
				flag2++;
			}
		}
		
		if(flag2 > 40){
			global.msgType = FAR_AWAY;
		}
		PIF = 0x00;//clear interrupt flag
	}
}

void App_GpioIntEnable(void)
{
	set_EPI;
}
void App_GpioIntDisable(void)
{
	clr_EPI;
}

void App_GpioConfig(void)
{
	// P1.7 Connect Irda, far from skin ,trig intterupt, high level trig, sch GP0
	P17_Input_Mode;
	//P17 = 0;
	// P1.5 Connect for wire cut, fall edge interupt, btw, if mcu in sleep mode wake up mcu.
	P15_Quasi_Mode;
	P15 = 1;
	//set_P0S_7;
	Enable_INT_Port1;
	//Enable_BIT5_LowLevel_Trig;
	//Enable_BIT5_HighLevel_Trig;
	Enable_BIT5_FallEdge_Trig;
	Enable_BIT7_RasingEdge_Trig;
	//Enable_BIT7_HighLevel_Trig;
	
	//set_EPI;							// Enable pin interrupt
	//set_EX0;							// enable ext0
  //set_EA;								// global enable bit
	// module gpip config : P0.0 OUTPUT sch PWRKEY_MCU, P0.2 OUTPUT High power on SCH POWER_CTL0
	P00_PushPull_Mode;
	P01_PushPull_Mode;
	
	P00 = 0;
	P01 = 0;
}

void App_CutWire(void)
{	
	
	while(1){
		if(gCutWireFlag){
			//App_SendString("cut", 3);
			App_EvbLedBlink();
			gCutWireFlag = 0;
		}
	}
}

void App_FarAway(void)
{	
	App_GpioIntEnable();
	while(1){
		if(gFarAwayFlag){
			//App_SendString("cut", 3);
			App_EvbLedBlink();
			gFarAwayFlag = 0;
		}
		if(gCutWireFlag){
			//App_SendString("cut", 3);
			App_EvbLedBlink();
			gCutWireFlag = 0;
		}
	}
}

#if 1
void App_ModulePowerON(void)
{
	P01 = 1;
	Timer0_Delay1ms(2000);
	P00 = 0;
	Timer0_Delay1ms(100);
	P00 = 1;
	Timer0_Delay1ms(2200);
	P00 = 0;
	global.moduleStatus = 1;
}

void App_ModulePowerOFF(void)
{
	P00 = 0;
	Timer0_Delay1ms(100);
	P00 = 1;
	Timer0_Delay1ms(2000);
	P00 = 0;
	Timer0_Delay1ms(100);
	P01 = 0;
	global.moduleStatus = 0;
}

void App_ModuleReset(void)
{
	App_ModulePowerOFF(); 
	Timer0_Delay1ms(1000);

	App_ModulePowerON();
	Timer0_Delay1ms(1000);
	App_GlobalInit();
}

void App_ModuleWait(UINT8 min)
{
	UINT16 i;
	for( i= 0; i<min*60; i++){
		Timer0_Delay1ms(1000);
	}
}
void App_ModuleWaitSec(UINT8 sec)
{
	UINT16 i;
	for( i= 0; i<sec; i++){
		Timer0_Delay1ms(1000);
	}
}
#endif
void App_Uart0Config(UINT32 u32Baudrate)
{
	// interrup mode
		P06_Quasi_Mode;
		P07_Quasi_Mode;
	
		SCON = 0x50;//0xD0;			// Special setting the mode 3 and 
		TMOD |= 0x20;    	//Timer1 Mode1
    
    set_SMOD;        	//UART0 Double Rate Enable
    set_T1M;
    clr_BRCK;        	//Serial port 0 baud rate clock source = Timer1
		TH1 = 256 - (1000000/u32Baudrate+1);               /*16 MHz */
		
		set_TR1;
	
		//set_RB8;					//This bit is for setting the stop bit 2 high/low status, 
	
		clr_TI; 
    set_ES;           //enable UART interrupt
    set_EA;           //enable global interrupt
}

void App_WakeUpTimeConfig(void)
{
	// set wakeup
	//-----------------------------------------------------
	//	WKT initial 	
	//-----------------------------------------------------	
		WKCON = 0x05; 										// timer base 10k, Pre-scale = 1/512
		WKCON = 0x07; 										// timer base 10k, Pre-scale = 1/2048
	/*
		RWK = 60000ms/204.8ms 
	*/									
		//RWK = 244;												// 50s if prescale is 0x00, never set RWK = 0xff
		//RWK = 25;												// 5s if prescale is 0x00, never set RWK = 0xff
		RWK = 0x00;
	  set_EWKT;													// enable WKT interrupt
		set_WKTR; 												// Wake-up timer run 
		//EA = 1;
}

void App_EnterPowerDown(void)
{
	App_GpioIntEnable();
	SerialPort0DisableInt();
	set_PD;
	SerialPort0EnableInt();
	App_GpioIntDisable();
}

void App_PowerDown(void)
{
	//App_GpioIntEnable();
	App_EvbLedOFF();
	Timer0_Delay1ms(50);
	App_EvbLedON();
	Timer0_Delay1ms(50);
	App_EvbLedOFF();
	Timer0_Delay1ms(50);
	Timer0_Delay1ms(500);
	Timer0_Delay1ms(500);
	Timer0_Delay1ms(500);
	Timer0_Delay1ms(500);
	
	
//	App_WakeUpTimeConfig();	
//	App_GlobalInterrupEnable();
//	App_EnterPowerDown();
	App_Uart0SendStrings("Frist run");
	App_EvbLedON();
	
//	while(1)
//	{
//		Timer0_Delay1ms(500);
//		Timer0_Delay1ms(500);
//		Timer0_Delay1ms(500);
//		Timer0_Delay1ms(500);
//		App_WakeUpTimeConfig();	
//		App_EnterPowerDown();
//		Timer0_Delay1ms(500);
//		Timer0_Delay1ms(500);
//		Timer0_Delay1ms(500);
//		Timer0_Delay1ms(500);
//	}
////	while(1){	
////		if(WKT_FLAG){ // 
////			// do somthing	
////			App_Uart0SendStrings("Wakeup Do something");			
////			App_ModulePowerON();

////			Timer0_Delay1ms(50);
////			Timer0_Delay1ms(1000);
////			Timer0_Delay1ms(1000);
////			Timer0_Delay1ms(1000);
////			Timer0_Delay1ms(1000);
////			u32WakeupCounter = 0;
////			App_ModulePowerOFF(); 
////			Timer0_Delay1ms(1000);
////			Timer0_Delay1ms(1000);
////			Timer0_Delay1ms(1000);
////			Timer0_Delay1ms(1000);
////			WKT_FLAG = 0;
////			
////		}
////		else{
////			Timer0_Delay1ms(1000);
////			App_Uart0SendStrings("Enter power down");
////			App_WakeUpTimeConfig();	
////			App_EnterPowerDown();
////			
////			
////			Timer0_Delay1ms(1000);
////			App_Uart0SendStrings("continue power down");
////		}
////	}
}

void App_TransMessageToModule(MsgType msgType)
{
  App_Send_TypeDef SendData;
  unsigned char len = 0;	
	
  SendData.ucHeader[0] = 'U';
  len++;
  SendData.ucHeader[1] = 'C';
  len++;
  SendData.ucCmdCode = msgType;
  len++;
  SendData.Data.end = 0xAA;
  len++;
	App_SendString((unsigned char *)&SendData, len);
	global.uartRxMode = PEND;
	SerialPort0EnableInt();
}

UINT8 App_ProcessReceiveMessageFromModule(UINT8 *buffer)
{
	const UINT8 *recStrTable[] = {"OK", "ERROR"};
	
	UINT16 i = 0;
	UINT8 ret = 0xFF;

  UINT8 *p = buffer;
	UINT8 tm[2];	

	while('U' == *p || 'C' == *p){
		p++;
	}
	if('+' == *p){
		tm[0] = *(++p);
		tm[1] = *(++p);
		global.pdIntCounter = tm[0]*10 + tm[1];
		ret = RET_TIME;			
	}
	for(i = 0; i<sizeof(recStrTable)/sizeof(recStrTable[0]); i++){
		if(strncmp(recStrTable[i], p, strlen(recStrTable[i])) == 0){
				ret = i; // 0,1
				break;
		}
	}	
	App_ClearRxBuffer();
	return ret;
  
//  App_Uart0SendStrings(buffer);
//	App_Uart0SendStrings("\r\n");
//  

//  if(strncmp(recStrTable[0], p, strlen(recStrTable[0])) == 0){
//     App_Uart0SendStrings("OK!\r\n");
//  }
//  else if(strncmp(recStrTable[1], p, strlen(recStrTable[1])) == 0){  
//     App_Uart0SendStrings("ERROR!\r\n");  
//  }
//  else{
//     App_Uart0SendStrings("NO INFO!\r\n");
//  }
}

char String[] = "App_SendString";
void App_Message(void)
{
	UINT8 Buf[30];
	UINT8 *rxBuf;
	int len;
	UINT8 ret;
	while(1){
		App_TransMessageToModule(0);
		Timer0_Delay1ms(500);
		
		App_TransMessageToModule(1);
		Timer0_Delay1ms(500);
		
		App_TransMessageToModule(2);
		Timer0_Delay1ms(500);
		
		
		
//		memset(Buf, 0x00, sizeof(Buf));
//		len = sprintf(Buf, "UC%s", "ERROR");
//    Buf[len] = 0xAA;
//    ret = App_ProcessReceiveMessageFromModule(Buf);    
//    Send_Data_To_UART0(ret);
//		Timer0_Delay1ms(500);
//		memset(Buf, 0x00, sizeof(Buf));
//    len = sprintf(Buf, "UC%s", "OK");
//    Buf[len] = 0xAA;
//    ret = App_ProcessReceiveMessageFromModule(Buf);
//		Send_Data_To_UART0(ret);
//		Timer0_Delay1ms(500);
//		memset(Buf, 0x00, sizeof(Buf));
//	
//		Buf[0] = 'U';
//		Buf[1] = 'C';
//		Buf[2] = '+';
//		Buf[3] = 0x5;
//		Buf[4] = 0x6;
//    Buf[5] = 0xAA;
//		Buf[5] = 0xAA;
//		Buf[5] = 0xAA;
//		
//    ret = App_ProcessReceiveMessageFromModule(Buf);
//		Send_Data_To_UART0(ret);
//		Timer0_Delay1ms(500);
		while(1){
			if(global.uartRxMode == END){
				rxBuf = UART0_RxBuf;
				ret = App_ProcessReceiveMessageFromModule(rxBuf);
				Send_Data_To_UART0(ret);
				global.uartRxMode = PEND;
				set_ES;
				break;
			}
		}
	}
}


/******************************************************************************
The main C function.  Program execution starts
here after stack initialization.
******************************************************************************/
#define RSP_TIMEOUT  100
#define MSG_TIMEOUT	 100
void main (void) 
{	
	UINT8 *rxBuf;	
	UINT16 counter = 0;
	UINT16 waitRspCnt = 0;
	UINT16 waitMsgCnt = 0;
	UINT8 waitRstCnt = 0;
	UINT16 wait_cnt = 0;
	UINT8 ret;
	UINT8 req_flag = 1;
	UINT8 msg_flag = 0;
	
	App_GpioConfig();
	App_GlobalInit();
	App_ModulePowerON();

	
	//App_GpioIntEnable();
	App_GlobalInterrupEnable();
	App_Uart0Config(9600);	
	App_Uart0SendStrings("AT\r\n");
	//App_Message();
	//App_PowerDown();
	//App_FarAway();

#if 1	
	//App_ModulePowerON();
	App_ModuleWait(1);
	//App_ModuleWaitSec(5);
	waitRspCnt = RSP_TIMEOUT;
	waitMsgCnt = MSG_TIMEOUT;
	while(1){
		switch(global.mode){
			case SEND_REQ:
				App_Uart0SendStrings("ENTER SEND REQ\r\n");
				waitRspCnt = RSP_TIMEOUT;
				App_TransMessageToModule(REQ_RESP);				
				global.mode = WAIT;
				req_flag = 1;
				msg_flag = 0;
				break;
			case SEND_MSG:
				App_Uart0SendStrings("ENTER SEND TYPE: ");
			  //App_Uart0SendStrings((UINT8 *)&global.msgType);
				waitMsgCnt = MSG_TIMEOUT;
				Send_Data_To_UART0(global.msgType+0x30);
				App_Uart0SendStrings("\r\n");
				App_TransMessageToModule(global.msgType);				
				global.mode = WAIT;
				req_flag = 0;
				msg_flag = 1;
				break;
			case PD:
				App_Uart0SendStrings("ENTER PD\r\n");
				if(global.moduleStatus == 1){
					App_ModulePowerOFF();
				}				
				App_WakeUpTimeConfig(); // update powerdonw counter 
				App_EnterPowerDown();
				
				if(global.msgType == CUT_WIRE || global.msgType == FAR_AWAY){
					clr_EWKT;
					global.mode = SEND_REQ;
					Timer0_Delay1ms(50);
					App_Uart0SendStrings("wakeup TYPE: ");
					Send_Data_To_UART0(global.msgType+0x30);
					App_Uart0SendStrings("\r\n");
					App_ModulePowerON();
					App_ModuleWaitSec(5);				
					//Timer0_Delay1ms(3000);
				}
				else {
					if(u32WakeupCounter < global.pdIntCounter){
						App_Uart0SendStrings("ENTER PD again\r\n");
						global.mode = PD;
						clr_WKTR;
					}
					else{
						Timer0_Delay1ms(1000);
						App_Uart0SendStrings("exit PD\r\n");
						global.msgType = POSTION;
						clr_EWKT;
						clr_WKTR;
						u32WakeupCounter = 0;
						global.mode = SEND_REQ;
						App_ModulePowerON();
						App_ModuleWaitSec(5);						
						//Timer0_Delay1ms(3000);						
					}
				}
				break;
			case COUNTER:
				App_Uart0SendStrings("Enter Counter\r\n");
				
				Timer0_Delay1ms(1000);
				if(msg_flag){
					if(--waitMsgCnt <= 0){
						global.mode = SEND_MSG;
						waitRstCnt++;
						break;
					}
				}
				if(req_flag){
					if(--waitRspCnt <= 0){
						global.mode = SEND_REQ;
						waitRstCnt++;
						break;
					}
				}
				global.mode = WAIT;
				if(waitRstCnt >= 3){
					App_Uart0SendStrings("Reset Module\r\n");
					App_ModuleReset();
					waitRstCnt = 0;
					App_Uart0SendStrings("Reset Module done\r\n");
				}	
				Send_Data_To_UART0_Debug(waitMsgCnt/10+0x30);
				Send_Data_To_UART0_Debug(waitMsgCnt%10+0x30);
				App_Uart0SendStrings(" waitMsgCnt \r\n");
				Send_Data_To_UART0_Debug(waitRspCnt/10 + 0x30);
				Send_Data_To_UART0_Debug(waitRspCnt%10 + 0x30);
				App_Uart0SendStrings(" waitRspCnt \r\n");				
				break;
			case WAIT: // wait message
				if(global.uartRxMode == END){					
					rxBuf = UART0_RxBuf;
					ret = App_ProcessReceiveMessageFromModule(rxBuf);
					if(ret == RET_OK){
						App_Uart0SendStrings("OK\r\n");
						waitRstCnt = 0;
						global.mode = SEND_MSG;						
					}
					else if(ret == RET_ERROR){
						App_Uart0SendStrings("ERROR\r\n");
					}
					else if(ret == RET_TIME){
						Send_Data_To_UART0_Debug(global.pdIntCounter+0x30);
						App_Uart0SendStrings("update TIME\r\n");
						global.mode = PD;
						//global.pdIntCounter = POWER_DOWN_TIME; // update time
					}
					waitRstCnt = 0;				
				}
				else{
					App_Uart0SendStrings("Wait to Counter Mode\r\n");
					global.mode = COUNTER;
				}
				break;
		}
	}
	#endif

}

